package com.example.user.service.bootstrap.security.config;



import com.example.user.adapter.out.persistence.service.CustomUserDetailsService;
import com.example.user.service.bootstrap.security.filter.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.List;

/**
 * Spring Security 配置类
 * 支持JWT认证和跨域配置
 * 
 * 这个类负责配置整个应用程序的安全策略，包括：
 * 1. 用户认证和授权规则
 * 2. JWT Token验证
 * 3. 跨域资源共享(CORS)配置
 * 4. 会话管理策略
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class BasicSecurityConfig {

    /**
     * JWT认证过滤器
     * 用于拦截请求并验证JWT Token的有效性
     */
    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    
    /**
     * 自定义用户详情服务
     * 用于加载用户信息进行认证
     */
    private final CustomUserDetailsService userDetailsService;



    /**
     * 认证管理器
     * 负责处理用户认证请求
     * 
     * @param config 认证配置对象，由Spring自动注入
     * @return AuthenticationManager 认证管理器实例
     * @throws Exception 如果配置过程中出现异常
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

    /**
     * CORS配置源
     * 配置跨域资源共享策略，允许前端应用访问后端API
     * 
     * @return CorsConfigurationSource CORS配置源
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        
        // 允许的源（Origin），这里设置为允许所有域名访问
        // 在生产环境中应该设置为具体的域名以提高安全性
        configuration.setAllowedOriginPatterns(List.of("*"));
        
        // 允许的HTTP方法，包括常用的GET、POST、PUT、DELETE等
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
        
        // 允许的请求头，这里设置为允许所有请求头
        configuration.setAllowedHeaders(List.of("*"));
        
        // 允许携带凭证（如Cookie），设置为true表示允许跨域请求携带身份信息
        configuration.setAllowCredentials(true);
        
        // 预检请求的缓存时间，单位秒，这里设置为1小时
        configuration.setMaxAge(3600L);
        
        // 暴露给客户端的响应头，允许客户端访问这些响应头
        configuration.setExposedHeaders(Arrays.asList("Authorization", "Content-Type"));
        
        // 创建基于URL的CORS配置源
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        // 对所有路径应用相同的CORS配置
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    /**
     * 安全过滤器链配置
     * 定义HTTP请求的安全处理规则
     * 
     * @param http HttpSecurity对象，用于配置Web安全
     * @return SecurityFilterChain 安全过滤器链
     * @throws Exception 如果配置过程中出现异常
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                // 禁用CSRF（跨站请求伪造）保护
                // 前后端分离项目通常禁用，因为使用Token认证而不是Session
                .csrf(AbstractHttpConfigurer::disable)
                
                // 启用CORS（跨域资源共享）并使用上面定义的配置
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                
                // 配置会话管理为无状态
                // 因为使用JWT Token认证，不需要服务器保存会话状态
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                
                // 配置请求授权规则
                .authorizeHttpRequests(authz -> authz
                        // 公开接口，无需认证即可访问
                        .requestMatchers("/api/auth/login", "/api/auth/register").permitAll()
                        .requestMatchers("/api/auth/debug/**").permitAll()
                        // Swagger和knife4j文档接口放行，方便查看API文档
                        .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**").permitAll()
                        .requestMatchers("/doc.html", "/webjars/**", "/favicon.ico").permitAll()
                        .requestMatchers("/actuator/**").permitAll()
                        .requestMatchers("/error").permitAll()
                        // 其他所有请求都需要认证
                        .anyRequest().authenticated()
                )
                
                // 禁用默认的登录页面
                // 因为使用自定义的登录接口，不需要Spring Security提供的默认登录页面
                .formLogin(AbstractHttpConfigurer::disable)
                
                // 禁用默认的登出页面
                // 因为使用自定义的登出接口，不需要Spring Security提供的默认登出功能
                .logout(AbstractHttpConfigurer::disable)
                
                // 禁用HTTP Basic认证
                // 因为使用JWT Token认证，不需要HTTP Basic认证方式
                .httpBasic(AbstractHttpConfigurer::disable)
                
                // 添加JWT认证过滤器
                // 在用户名密码认证过滤器之前添加JWT认证过滤器
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                
                // 配置用户详情服务
                // 用于加载用户信息进行认证
                .userDetailsService(userDetailsService)
                
                // 配置异常处理
                .exceptionHandling(exceptions -> exceptions
                        // 认证入口点，当未认证用户访问需要认证的资源时调用
                        .authenticationEntryPoint((request, response, authException) -> {
                            response.setStatus(401);
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().write("{\"code\":401,\"message\":\"未授权访问，请先登录\",\"data\":null}");
                        })
                        // 访问拒绝处理器，当已认证用户访问没有权限的资源时调用
                        .accessDeniedHandler((request, response, accessDeniedException) -> {
                            response.setStatus(403);
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().write("{\"code\":403,\"message\":\"访问被拒绝，权限不足\",\"data\":null}");
                        })
                );

        return http.build();
    }
}
